package p17_从advisor到aspect;

import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * 代理对象的创建时机
 * aop会在两个阶段创建代理
 * 创建对象 ->(*)依赖注入 -> 初始化(*)  两个位置二选一
 * 1.初始化之后(无循环依赖)
 * 2.实例创建后，依赖注入前(有循环依赖)，并暂存与二级缓存
 * 依赖注入和初始化方法不应该被增强，如果是依赖注入前创建了代理，那么该bean的后续生命周期仍然调用的是原始对象的生命周期方法
 */
@Configuration
public class _2_创建代理的时机 {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
        context.registerBean(CommonAnnotationBeanPostProcessor.class);
        context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
        context.registerBean(_2_创建代理的时机.class);
        context.refresh();
        /**
         * 通过观察日志打印(trace级别)，可以得知代理的创建时机
         *  1.一般情况下，代理的创建是在初始化之后
         *  2.如果有循环依赖，则代理的创建提前到了依赖注入之前，并将代理暂存二级缓存，后续的依赖注入和初始化方法还是使用的原始bean，初始化后才用代理来顶替原始bean
         * 依赖注入方法和初始化方法本身不应该被增强(初始化之后，bean被准备好，所以在bean准备好之前都不应该被增强，这也是为什么创建代理提前到了依赖注入之前时，需要暂存代理类)
         */
        }

    @Component
    static class Bean1 {
        public void bar() {
        }

        public Bean1() {
            System.out.println("bean1被创建啦...");
        }

        @PostConstruct
        public void init() {
            System.out.println("bean1被初始化啦...");
        }
    }

    @Component
    static class Bean2 {
        public Bean2() {
            System.out.println("bean2被创建啦...");
        }

        @Autowired
        public void setBean1(Bean1 bean1) {
            System.out.println("bean2依赖注入了bean1..." + bean1);
        }

        @PostConstruct
        public void init() {
            System.out.println("bean2被初始化啦...");
        }
    }

    @Bean
    public Advisor advisor() {
        AspectJExpressionPointcut pt = new AspectJExpressionPointcut();
        pt.setExpression("execution(* bar())");
        return new DefaultPointcutAdvisor(pt, (MethodInterceptor) invocation -> {
            System.out.println("前置通知...");
            Object proceed = invocation.proceed();
            System.out.println("后置通知...");
            return proceed;
        });
    }
}
